'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with self work for additional information
 * regarding copyright ownership.  The ASF licenses self file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use self file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http:#www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''
from base.java.exception.IllegalStateException import IllegalStateException
from base.rdf.EmptyListException import EmptyListException
from base.rdf.EmptyListUpdateException import EmptyListUpdateException
from base.rdf.InvalidListException import InvalidListException
from base.rdf.ListIndexException import ListIndexException
from base.rdf.RDFList import RDFList
from base.rdf.impl.ResourceImpl import ResourceImpl
from base.util.iterator.impl.NiceIterator import NiceIterator
from base.vocabulary.RDF import RDF

# Package
#######/


# Imports
#######/

#import java.util.*;
#import java.util.function.Function;

#import org.apache.jena.enhanced.*;
#import org.apache.jena.graph.*;
#import org.apache.jena.ontology.*;
#import org.apache.jena.rdf.model.*;
#import org.apache.jena.shared.*;
#import org.apache.jena.util.iterator.*;
#import org.apache.jena.vocabulary.*;
#import org.slf4j.Logger;
#import org.slf4j.LoggerFactory;


'''
 * <p>
 * Standard implementation the list abstraction from rdf.model.
 * </p>
'''
class RDFListImpl(ResourceImpl, RDFList):
    # Constants
    #################


    # Static variables
    #################

    '''
     * A factory for generating RDFList facets from nodes in enhanced graphs.
    '''
    # @SuppressWarnings("hiding")
    # param 
    # result static Implementation factory = new
    """
    def Implementation factory = Implementation(self):
        # @Override
    # param Node n, EnhGraph eg
    # result EnhNode
    def wrap(self, n, eg):
            if (canWrap(n, eg)):
                RDFListImpl impl = RDFListImpl(n, eg)

                # pass on the vocabulary terms, if available
                if (eg instanceof OntModel):
                    Profile prof = ((OntModel) eg).getProfile()
                    impl.m_listFirst = prof.FIRST()
                    impl.m_listRest = prof.REST()
                    impl.m_listNil = prof.NIL()
                    impl.m_listType = prof.LIST()
                

                return impl
            else:
                raise JenaException("Cannot convert node " + n + " to RDFList")
            
        

        # @Override
    # param Node node, EnhGraph eg
    # result boolean
    def canWrap(self, node, eg):
            Graph g = eg.asGraph()

            # if we are using a language profile, get the first, rest and next resources from there
            Resource first = RDF.first
            Resource rest = RDF.rest
            # Resource
        nil = RDF.nil

            if (eg instanceof OntModel):
                Profile prof = ((OntModel) eg).getProfile()
                first = prof.FIRST()
                rest = prof.REST()
                nil = prof.NIL()
            

            # node will support being an RDFList facet if it has rdf:type rdf:List, is nil, or is in the domain of a list property
            return
                    node.equals(nil.asNode()) or
                            g.contains(node, first.asNode(), Node.ANY) or
                            g.contains(node, rest.asNode(), Node.ANY) or
                            g.contains(node, RDF.type.asNode(), RDF.List.asNode())
        
    """

    '''
     * Flag to indicate whether we are checking for valid lists during list operations. Default False.
    '''
    # protected static boolean 
    s_checkValid = False

    # param RDFListImpl.class
    # result static final Logger log = LoggerFactory.getLogger(self)


    # Instance variables
    #################

    '''
     * Error message if validity check fails
    '''
    # protected String
    m_errorMsg = None

    '''
     * Pointer to the node that is the tail of the list
    '''
    # protected RDFList
    m_tail = None

    '''
     * The URI for the 'first' property in self list
    '''
    # protected Property
    m_listFirst = RDF.first

    '''
     * The URI for the 'rest' property in self list
    '''
    # protected Property
    m_listRest = RDF.rest

    '''
     * The URI for the 'nil' Resource in self list
    '''
    # protected Resource
    m_listNil = RDF.nil

    '''
     * The URI for the rdf:type of self list
    '''
    # protected Resource
    m_listType = RDF.List


    # Constructors
    #################

    '''
     * <p>
     * Construct an implementation of RDFList in the given graph, where the
     * given node is the head of the list.
     * </p>
     *
     * @param n The node that is the head of the list, currently
     * @param g The enh graph that contains n
    '''
    # param Node n, EnhGraph g
    def __init__(n, g):
        super().__init__(n, g)
    


    # External signature methods
    #################

    # vocabulary terms
    # param 
    # result Resource
    def listType(self):
        return self.m_listType
    

    # param 
    # result Resource
    def listNil(self):
        return self.m_listNil
    

    # param 
    # result Property
    def listFirst(self):
        return self.m_listFirst
    

    # param 
    # result Property
    def listRest(self):
        return self.m_listRest
    

    # param 
    # result Class<? extends RDFList>
    def listAbstractionClass(self):
        return RDFList.__class__
    


    '''
     * <p>
     * Answer the number of elements in the list.
     * </p>
     *
     * @return The length of the list as an integer
    '''
    # @Override
    # param 
    # result int
    def size(self):
        if (self.s_checkValid):
            self.selfcheckValid()

        size = 0
    
        i = self.iterator()
        while i.hasNext():
            i.next()
            size += 1
        
        #for (Iterator<RDFNode> i = self.iterator() i.hasNext() i.next()):
            #size += 1
        
        return size
    


    '''
     * <p>
     * Answer the value that is at the head of the list.
     * </p>
     *
     * @return The value that is associated with the head of the list.
     * @throws EmptyListException if self list is the empty list
    '''
    # @Override
    # param 
    # result RDFNode
    def getHead(self):
        if (self.s_checkValid):
            self.checkValid()
        

        self.checkNotNil("Tried to get the head of an empty list")

        return self.getRequiredProperty(self.listFirst()).getObject()
    


    '''
     * <p>
     * Update the head of the list to have the given value, and return the
     * previous value.
     * </p>
     *
     * @param value The value that will become the value of the list head
     * @throws EmptyListException if self list is the empty list
    '''
    # @Override
    # param RDFNode value
    # result RDFNode
    def setHead(self, value):
        if (self.s_checkValid):
            self.checkValid()
        

        self.checkNotNil("Tried to set the head of an empty list")

        # first remove the existing head
        # Statement 
        current = self.getRequiredProperty(self.listFirst())
        # RDFNode 
        n = current.getObject()
        current.remove()

        # now add the head value to the graph
        self.addProperty(self.listFirst(), value)

        return n
    


    '''
     * <p>
     * Answer the list that is the tail of self list.
     * </p>
     *
     * @return The tail of the list, as a list
     * @throws EmptyListException if self list is the empty list
    '''
    # @Override
    # param 
    # result RDFList
    def getTail(self):
        if (self.s_checkValid):
            self.checkValid()
        

        self.checkNotNil("Tried to get the tail of an empty list")

        # Resource 
        tail = self.getRequiredProperty(self.listRest()).getResource()
        return tail.asClass(self.listAbstractionClass())
    


    '''
     * <p>
     * Update the list cell at the front of the list to have the given list as
     * tail. The old tail is returned, and remains in the model.
     * </p>
     *
     * @param tail The tail for self list.
     * @return The old tail.
    '''
    # @Override
    # param RDFList tail
    # result RDFList
    def setTail(self, tail):
        if (self.s_checkValid):
            self.checkValid()
        

        self.checkNotNil("Tried to set the tail of an empty list")

        return (RDFListImpl.setTailAux(self, tail, self.listRest())).asClass(self.listAbstractionClass())
    


    '''
     * Answer True if self list is the empty list.
     *
     * @return True if self is the empty (nil) list, otherwise False.
    '''
    # @Override
    # param 
    # result boolean
    def isEmpty(self):
        if (self.s_checkValid):
            self.checkValid()
        

        return self.equals(self.listNil())
    


    '''
     * <p>
     * Return a reference to a list cell whose head is <code>value</code>
     * and whose tail is self list.
     * </p>
     *
     * @param value A value to add to the head of the list
     * @return The list, whose head is <code>value</code>
    '''
    # @Override
    # param RDFNode value
    # result RDFList
    def cons(self, value):
        if (self.s_checkValid):
            self.checkValid()
        

        # create a new, anonymous typed resource to be the list cell
        # map to a list facet
        return (self.newListCell(value, self)).asClass(self.listAbstractionClass())
    


    '''
     * <p>
     * Add the given value to the end of the list. This is a side-effecting
     * operation on the underlying model that is only defined if self is not the
     * empty list.  If self list is the empty (nil) list, we cannot perform a
     * side-effecting update without changing the URI of self node (from <code>rdf:nil</code>)
     * to a blank-node for the list cell) without violating a Jena invariant.
     * Therefore, self update operation will throw an exception if an attempt is
     * made to add to the nil list.  Safe ways to add to an empty list include
     *:@link #withand:@link #cons.
     * </p>
     *
     * @param value A value to add to the end of the list
     * @throws EmptyListUpdateException if an attempt is made to
     *                                  <code>add</code> to the empty list.
    '''
    # @Override
    # param RDFNode value
    # result void
    def add(self, value):
        if (self.s_checkValid):
            self.checkValid()
        

        # if self is the empty list, we have to barf
        if (self.isEmpty()):
            raise EmptyListUpdateException("Attempt to add() to the empty list (rdf:nil)")
        

        # get the tail of the list (which may be cached)
        # RDFList
        tail = self.findElement(True, 0)

        # now do the concatenate
        RDFListImpl.setTailAux(tail, self.newListCell(value, self.listNil()), self.listRest())
    


    '''
     * <p>
     * Answer the list that is self list with the given value added to the end
     * of the list.  This operation differs from:@link #addin that it will
     * always work, even on an empty list, but the return value is the updated
     * list.  Specifically, in the case of adding a value to the empty list, the
     * returned list will not be the same as self list. <strong>Client code should
     * not assume that self is an in-place update, but should ensure that the resulting
     * list is asserted back into the graph into the appropriate relationships.</strong>
     * </p>
     *
     * @param value A value to add to the end of the list
     * @return The list that results from adding a value to the end of self list
    '''
    # @Override
    # param RDFNode value
    # result RDFList
    def withRDFNode(self, value):
        if (self.s_checkValid):
            self.checkValid()
        

        # if self is the empty list, we create a node containing value - i.e. cons
        if (self.isEmpty()):
            return self.cons(value)
        

        # get the tail of the list (which may be cached)
        # RDFList 
        tail = self.findElement(True, 0)

        # now do the concatenate
        self.setTailAux(tail, self.newListCell(value, self.listNil()), self.listRest())
        return self
    


    '''
     * <p>
     * Answer the node that is the i'th element of the list, assuming that the
     * head is item zero.  If the list is too short to have an i'th element,
     * throws a:@link ListIndexException.
     * </p>
     *
     * @param i The index into the list, from 0
     * @return The list value at index i, or None
     * @throws ListIndexException if the list has fewer than (i + 1)
     *                            elements.
    '''
    # @Override
    # param int i
    # result RDFNode
    def get(self, i):
        if (self.s_checkValid):
            self.checkValid()
        

        self.checkNotNil("Tried to get an element from the empty list")
        return self.findElement(False, i).getHead()
    


    '''
     * <p>
     * Replace the value at the i'th position in the list with the given value.
     * If the list is too short to have an i'th element, throws a:@link
     * ListIndexException.
     * </p>
     *
     * @param i     The index into the list, from 0
     * @param value The value to associate with the i'th list element
     * @return The value that was previously at position i in the list
     * @throws ListIndexException if the list has fewer than (i + 1)
     *                            elements.
    '''
    # @Override
    # param int i, RDFNode value
    # result RDFNode
    def replace(self, i, value):
        if (self.s_checkValid):
            self.checkValid()
        

        self.checkNotNil("Tried to replace a value in the empty list")
        return self.findElement(False, i).setHead(value)
    


    '''
     * <p>
     * Answer True if the given node appears as the value of a value of any
     * of the cells of self list.
     * </p>
     *
     * @param value A value to test for
     * @return True if the list contains value.
    '''
    # @Override
    # param RDFNode value
    # result boolean
    def contains(self, value):
        return self.indexOf(value, 0) >= 0
    


    '''
     * <p>
     * Answer the index of the first occurrence of the given value in the list,
     * or -1 if the value is not in the list.
     * </p>
     *
     * @param value The value to search for
     * @return The index of the first occurrence of value in the list, or
     * <code>-1</code> if not found.
    '''
    # @Override
    # param RDFNode value
    # result int
    def indexOf(self, value):
        return self.indexOfWithValueAndStart(value, 0)
    


    '''
     * <p>
     * Answer the index of the first occurrence of the given value in the list
     * after index <code>start</code>, or -1 if the value is not in the list
     * after the given start point.
     * </p>
     *
     * @param value The value to search for
     * @param start The index into the list to start searching from
     * @return The index (from zero, the front of the list) of the first
     * occurrence of <code>value</code> in the list not less than
     * <code>start</code>, or <code>-1</code> if not found.
     * @throws ListIndexException if <code>start</code> is greater than the
     *                            length of the list.
    '''
    # @Override
    # param RDFNode value, int start
    # result int
    def indexOfWithValueAndStart(self, value, start):
        if (self.s_checkValid):
            self.checkValid()
        

        # first get to where we start
        # Resource 
        l = self.findElement(False, start)
        # int 
        index = start

        # Property 
        head = self.listFirst()
        # Property 
        tail = self.listRest()
        # Resource 
        nil = self.listNil()

        # boolean 
        found = l.hasProperty(head, value)

        # search for the element whose value is, er, value
        while not found and not l.equals(nil):
            l = l.getRequiredProperty(tail).getResource()
            index += 1
            found = l.hasProperty(head, value)
        

        return index if found else -1
    


    '''
     * <p>
     * Answer a list that is formed by adding each element of self list to
     * the head of the the list formed from the
     * given <code>nodes</code>. This is a non side-effecting
     * operation on either self list or the given list, but generates a copy
     * of self list.  For a more storage efficient alternative, see:@link
     * #concatenate concatenate.
     * </p>
     *
     * @param nodes An iterator whose range is RDFNode
     * @return A RDFList that contains all of self elements of self list,
     * followed by all of the elements of the given iterator.
    '''
    # @Override
    # param Iterator<? extends RDFNode> nodes
    # result RDFList
    def appendWithIterator(self, nodes):
        return self.append(self.copyWithIterator(nodes))
    


    '''
     * <p>
     * Answer a list that is formed by adding each element of self list to
     * the head of the given <code>list</code>. This is a non side-effecting
     * operation on either self list or the given list, but generates a copy
     * of self list.  For a more storage efficient alternative, see:@link
     * #concatenate concatenate.
     * </p>
     *
     * @param list The argument list
     * @return A RDFList that contains all of self elements of self list,
     * followed by all of the elements of the given list.
    '''
    # @Override
    # param RDFList list
    # result RDFList
    def append(self, list):
        if (self.s_checkValid):
            self.checkValid()
        

        if (self.isEmpty()):
            # special case
            return list
        else:
            # could do self recursively, but for long lists it's better to iterate
            # do the copy, then change the last tail pointer to point to the arg
            # RDFList 
            copy = self.copyWithIterator(self.iterator())
            copy.concatenate(self.list)
            return copy
        
    


    '''
     * <p>
     * Change the tail of self list to point to the given list, so that self
     * list becomes the list of the concatenation of the elements of both lists.
     * This is a side-effecting operation on self list for a non side-effecting
     * alternative, see:@link #append.  Due to the problem of maintaining
     * the URI invariant on a node, self operation will throw an exception if an
     * attempt is made to concatenate onto an empty list.  To avoid self, test for
     * an empty list: if True replace the empty list with the argument list, otherwise
     * proceed with the concatenate as usual.  An alternative solution is to use
     *:@link #appendand replace the original list with the return value.
     * </p>
     *
     * @param list The argument list to concatenate to self list
     * @throws EmptyListUpdateException if self list is the nil list
    '''
    # @Override
    # param RDFList list
    # result void
    def concatenate(self, list):
        if (self.s_checkValid):
            self.checkValid()
        

        if (self.isEmpty()):
            # concatenating list onto the empty list is an error
            raise EmptyListUpdateException("Tried to concatenate onto the empty list")
        else:
            # find the end of self list and link it to the argument list
            self.findElement(True, 0).setTail(self.list)
        
    


    '''
     * <p>
     * Add the nodes returned by the given iterator to the end of self list.
     * </p>
     *
     * @param nodes An iterator whose range is RDFNode
     * @throws EmptyListUpdateException if self list is the nil list
     * @see #concatenate(RDFList) for details on avoiding the empty list update exception.
    '''
    # @Override
    # param Iterator<? extends RDFNode> nodes
    # result void
    def concatenateWithIterator(self, nodes):
        # make a list of the nodes and add to the end of self
        self.concatenate(self.copyWithIterator(nodes))
    


    '''
     * <p>
     * Answer a list that contains all of the elements of self list in the same
     * order, but is a duplicate copy in the underlying model.
     * </p>
     *
     * @return A copy of the current list
    '''
    # @Override
    # param 
    # result RDFList
    def copy(self):
        if (self.s_checkValid):
            self.checkValid()
        

        return self.copyWithIterator(self.iterator())
    


    '''
     * <p>
     * Apply a function to each value in the list in turn.
     * </p>
     *
     * @param fn The function to apply to each list node.
    '''
    # @Override
    # param ApplyFn fn
    # result void
    def apply(self, fn):
        if (self.s_checkValid):
            self.checkValid()
        

        # for (Iterator<RDFNode> i = self.iterator() i.hasNext() ):
        i = self.iterator()
        while i.hasNext():
            fn.apply(i.next())
        
    


    '''
     * <p>
     * Apply a function to each value in the list in turn, accumulating the
     * results in an accumulator. The final value of the accumulator is returned
     * as the value of <code>reduce()</code>.
     * </p>
     *
     * @param fn      The reduction function to apply
     * @param initial The initial value for the accumulator
     * @return The final value of the accumulator.
    '''
    # @Override
    # param ReduceFn fn, Object initial
    # result Object
    def reduce(self, fn, initial):
        if (self.s_checkValid):
            self.checkValid()
        

        # Object 
        acc = initial

        # for (Iterator<RDFNode> i = self.iterator() i.hasNext() ):
        i = self.iterator()
        while i.hasNext():
            acc = fn.reduce(i.next(), acc)
        

        return acc
    


    '''
     * <p>Answer an iterator of the elements of self list, to each of which
     * the given map function has been applied.</p>
     *
     * @param fn A Map function
     * @return The iterator of the elements of self list mapped with the given map function.
    '''
    # @Override
    # param Function<RDFNode, T> fn
    # result <T> ExtendedIterator<T>
    def mapWith(self, fn):
        return self.iterator().mapWith(fn)
    

    '''
     * <p>
     * Remove the value from the head of the list.  The tail of the list remains
     * in the model.  Note that no changes are made to list cells that point to
     * self list cell as their tail.  Immediately following a
     * <code>removeHead</code> operation, such lists will be in a non-valid
     * state.
     * </p>
     *
     * @return The remainder of the list after the head is removed (i&#046e&#046 the
     * pre-removal list tail)
    '''
    # @Override
    # param 
    # result RDFList
    def removeHead(self):
        if (self.s_checkValid):
            self.checkValid()
        

        self.checkNotNil("Attempted to delete the head of a nil list")

        # RDFList 
        tail = self.getTail()
        self.removeProperties()

        return tail
    


    '''
     * <p>Remove the given value from self list. If <code>val</code> does not occur in
     * the list, no action is taken.  Since removing the head of the list will invalidate
     * the list head cell, in general the list must return the list that results from self
     * operation. However, in many cases the return value will be the same as the object
     * that self method is invoked on</p>
     *
     * @param val The value to be removed from the list
     * @return The resulting list, which will be the same as the current list in most
     * cases, except when <code>val</code> occurs at the head of the list.
    '''
    # @Override
    # param RDFNode val
    # result RDFList
    def remove(self, val):
        if (self.s_checkValid):
            self.checkValid()
        

        # RDFList 
        prev = None
        # RDFList
        cell = self
        # boolean
        searching = True

        while (searching and not cell.isEmpty()):
            if (cell.getHead().equals(val)):
                # found the value to be removed
                # RDFList 
                tail = cell.getTail()
                if (prev is not None):
                    prev.setTail(tail)
                

                cell.removeProperties()

                # return self unless we have removed the head element
                return tail if (prev is None) else self
            else:
                # not found yet
                prev = cell
                cell = cell.getTail()
            
        

        # not found
        return self
    

    '''
     * <p>Remove all of the components of self list from the model. Once self operation
     * has completed, the:@link RDFListresource on which it was called will no
     * longer be a resource in the model, so further methods calls on the list object
     * (for example,:@link #sizewill fail.  Due to restrictions on the encoding
     * of lists in RDF, it is not possible to perform an operation which empties a list
     * and then adds further values to that list. Client code wishing to perform
     * such an operation should do so in two steps: first remove the old list, then
     * create a list with the contents. It is important that RDF statements
     * that reference the old list (in the object position) be updated to point
     * to the newly created list.
     * Note that self
     * is operation is only removing the list cells themselves, not the resources
     * referenced by the list - unless being the object of an <code>rdf:first</code>
     * statement is the only mention of that resource in the model.</p>
    '''
    # @Override
    # param 
    # result void
    def removeList(self):
        # for (Statement statement : collectStatements()):
        for statement in self.collectStatements():
            statement.remove()
        
    
    def subWhile(self, l, stmts):
        i = l.listProperties()
        while i.hasNext():
            stmts.add(i.next())
            
        return l.getTail()
        

    '''
     * <p>Answer a set of all of the RDF statements whose subject is one of the cells
     * of self list.</p>
     *
     * @return A list of the statements that form the encoding of self list.
    '''
    # param 
    # result Set<Statement>
    def collectStatements(self):
        # Set<Statement> stmts = HashSet<>()
        stmts = set()
        # RDFList 
        l = self

        # i = l.listProperties()
        # stmts.add(i.next())
        # l = l.getTail()
        
        l = self.subWhile(l, stmts)
        while l.isEmpty():
            l = self.subWhle(l, stmts)
            
        
        # do:
            # collect all statements of self list cell
            # for (Iterator<Statement> i = l.listProperties() i.hasNext() ):
                # stmts.add(i.next())
            

            # move on to next cell
            # l = l.getTail()
        # while (not l.isEmpty())

        return stmts
    


    '''
     * <p>
     * Answer an iterator over the elements of the list. Note that self iterator
     * does not take a snapshot of the list, so changes to the list statements
     * in the model while iterating will affect the behaviour of the iterator.
     * To get an iterator that is not affected by model changes, use:@link
     * #asJavaList.
     * </p>
     *
     * @return A closable iterator over the elements of the list.
    '''
    # @Override
    # param 
    # result ExtendedIterator<RDFNode>
    def iterator(self):
        return RDFListIterator(self)
    


    '''
     * <p>
     * Answer the contents of self RDF list as a Java list of RDFNode values.
     * </p>
     *
     * @return The contents of self list as a Java List.
    '''
    # @Override
    # param 
    # result List<RDFNode>
    # def asJavaList(self):
    #     List<RDFNode> l = ArrayList<>()
    #
    #     for (Iterator<RDFNode> i = self.iterator() i.hasNext() ):
    #         l.add(i.next())
    #
    #
    #     return l
    


    '''
     * <p>
     * Answer True if self list has the same elements in the same order as the
     * given list.  Note that the standard <code>equals</code> test just tests
     * for equality of two given list cells.  While such a test is sufficient
     * for many purposes, self test provides a broader equality definition, but
     * is correspondingly more expensive to test.
     * </p>
     *
     * @param list The list to test against
     * @return True if the given list and self list are the same length, and
     * contain equal elements in the same order.
    '''
    # @Override
    # param RDFList list
    # result boolean
    def sameListAs(self, list):
        if (self.s_checkValid):
            self.checkValid()
        

        # Resource
        r0 = self
        r1 = self.list

        # Property
        head = self.listFirst()
        # Property
        tail = self.listRest()
        # Resource
        nil = self.listNil()

        # iterate through to the end of the list
        while (not (r0.equals(nil) or r1.equals(nil))):
            # RDFNode 
            n0 = r0.getRequiredProperty(head).getObject()
            # RDFNode 
            n1 = r1.getRequiredProperty(head).getObject()

            if (n0 is None or not n0.equals(n1)):
                # not equal at self position
                return False
            else:
                # advance along the lists
                r0 = r0.getRequiredProperty(tail).getResource()
                r1 = r1.getRequiredProperty(tail).getResource()
            
        

        # lists are equal if they terminate together
        return r0.equals(nil) and r1.equals(nil)
    


    '''
     * <p>
     * Answer True lists are operating in strict mode, in which the
     * well- formedness of the list is checked at every operation.
     * </p>
     *
     * @return True lists are being strictly checked.
    '''
    # @Override
    # param 
    # result boolean
    def getStrict(self):
        return self.s_checkValid
    


    '''
     * <p>
     * Set a flag to indicate whether to strictly check the well-formedness of
     * lists at each operation. Default False.  Note that the flag that is
     * manipulated is actually a static: it applies to all lists. However, RDFList
     * is a Java interface, and Java does not permit static methods in interfaces.
     * </p>
     *
     * @param strict The <b>static</b> flag for whether lists will be checked strictly.
    '''
    # @Override
    # param boolean strict
    # result void
    def setStrict(self, strict):
        self.s_checkValid = strict
    


    '''
     * <p>
     * Answer True if the list is well-formed, by checking that each node is
     * correctly typed, and has a head and tail pointer from the correct
     * vocabulary.
     * </p>
     *
     * @return True if the list is well-formed.
    '''
    # @Override
    # param 
    # result boolean
    def isValid(self):
        m_errorMsg = None

        try:
            self.checkValid()
        except InvalidListException as e:
            m_errorMsg = e.getMessage()
        

        return (m_errorMsg is None)
    


    '''
     * <p>
     * Answer the error message returned by the last failed validity check,
     * if any.
     * </p>
     *
     * @return The most recent error message, or None.
    '''
    # @Override
    # param 
    # result String
    def getValidityErrorMessage(self):
        return self.m_errorMsg
    


    '''
     * <p>
     * Construct a list cell with the given value and tail.
     * </p>
     *
     * @param value The value at the head of the list cell
     * @param tail  The tail of the list cell
     * @return A list cell as a resource
    '''
    # param RDFNode value, Resource tail
    # result Resource
    def newListCell(self, value, tail):
        # Note: following the RDF WG decision, we no longer assert rdf:type rdf:List for list cells
        # Resource
        cell = self.getModel().createResource()

        # set the head and tail
        cell.addProperty(self.listFirst(), value)
        cell.addProperty(self.listRest(), tail)

        return cell
    


    # Internal implementation methods
    #################

    '''
     * <p>
     * Answer True if self is a valid list cell, which means either that it
     * is nil, or it has the appropriate type and a first and next relation.
     * Updated 17-06-2003: RDFCore last comments process has decided that the
     * rdf:type of a list is implied by the domain constraints on rdf:first
     * and rdf:rest, so no longer needs to be asserted directly.  The test
     * for rdf:type has therefore been removed.
     * </p>
     *
     * @returns True if self list cell passes basic validity checks
    '''
    # param 
    # result void
    def checkValid(self):
        if (not self.equals(self.listNil())):
            # note that the rdf:type of list cells is now implied by the RDF M&S
            # so we don't check explicitly
            # checkValidProperty( RDF.type, listType() )

            self.checkValidProperty(self.listFirst(), None)
            self.checkValidProperty(self.listRest(), None)
        
    

    # param Property p, RDFNode expected
    # result void
    def checkValidProperty(self, p, expected):
        # int 
        count = 0

        # for (StmtIterator j = self.getModel().listStatements(self, p, expected) j.hasNext() j.next()):
        j = self.getModel().listStatements(self, p, expected)
        while j.hasNext():
            j.next()
            count += 1
        

        # exactly one value is expected
        if (count == 0):
            '''
            if (log.isDebugEnabled()):
                log.debug("Failed validity check on " + toString())
                for (StmtIterator i = self.listProperties() i.hasNext() ):
                    log.debug("  self => " + i.next())
                
                for (StmtIterator i = self.getModel().listStatements(None, None, self) i.hasNext() ):
                    log.debug("  => self " + i.next())
            '''    
            
            raise InvalidListException("List node " + self.toString() + " is not valid: it should have property " + \
                    p.toString() + \
                    ("" if expected is None else (" with value " + expected)))
        elif (count > 1):
            raise InvalidListException("List node " + self.toString() + " is not valid: it has more than one value for " + \
                    p.toString())
        
    


    '''
     * <p>
     * Check that the current list cell is not the nil list, and throw an empty
     * list exception if it is.
     * </p>
     *
     * @param msg The context message for the empty list exception
     * @throws EmptyListException if the list is the nil list
    '''
    # param String msg
    # result void
    def checkNotNil(self, msg):
        if (self.isEmpty()):
            raise EmptyListException(msg)
        
    


    '''
     * <p>
     * Find and return an element of self list - either the last element before
     * the end of the list, or the i'th element from the front (starting from
     * zero).  Note that self method assumes the pre-condition that
     * <code>self</code> is not the empty list.
     * </p>
     *
     * @param last  If True, find the element whose tail is nil
     * @param index If <code>last</code> is False, find the index'th element
     *              from the head of the list
     * @return The list cell
     * @throws ListIndexException   if try to access an element beyond the end
     *                              of the list
     * @throws InvalidListException if try to find the end of a badly formed
     *                              list
    '''
    # param boolean last, int index
    # result RDFList
    def findElement(self, last, index):
        # Property
        tail = self.listRest()
        # Resource
        nil = self.listNil()

        # Resource 
        l = self
        # int 
        i = index
        # boolean 
        found = (last and l.hasProperty(tail, nil)) or (not last and (i == 0))

        # search for the element whose tail is nil, or whose index is now zero
        while (not found and not l.equals(nil)):
            l = l.getRequiredProperty(tail).getResource()
            if not last:
                i = i - 1
            found = (last and l.hasProperty(tail, nil)) or (not last and (i == 0))
        

        if (not found):
            # premature end of list
            if (not last):
                raise ListIndexException("Tried to access element " + index + " that is beyond the length of the list")
            else:
                raise InvalidListException("Could not find last element of list (suggests list is not valid)")
            
        else:
            return l.asClass(self.listAbstractionClass())
        
    


    '''
     * <p>
     * Create a copy of the list of nodes returned by an iterator.
     * </p>
     *
     * @param i An iterator of RDFNodes
     * @return A list formed from all of the nodes of i, in sequence
    '''
    # param Iterator<? extends RDFNode> i
    # result RDFList
    def copyWithIterator(self, i):
        # Resource 
        list = None
        # Resource 
        start = None

        # Property
        head = self.listFirst()
        # Property
        tail = self.listRest()
        # Resource
        cellType = self.listType()

        if (i.hasNext()):
            while (i.hasNext()):
                # create a list cell to hold the next value from the existing list
                # Resource
                cell = self.getModel().createResource(cellType)
                cell.addProperty(head, i.next())

                # point the previous list cell to self one
                if (self.list is not None):
                    list.addProperty(tail, cell)
                else:
                    # must be the first cell we're adding
                    start = cell
                

                list = cell
            

            # finally close the list
            list.addProperty(tail, self.listNil())
        else:
            # create an empty list
            start = self.getModel().createList()
        

        return start.asClass(self.listAbstractionClass())
    


    '''
     * <p>
     * Helper method for setting the list tail, that assumes we have
     * a resource that is a list.
     * </p>
     *
     * @param root The resource representing the list cell we're setting the
     *             tail of
     * @param tail The tail for self list, as a resource.
     * @return The old tail, as a resource.
    '''
    # param Resource root, Resource tail, Property pTail
    # result static Resource
    @staticmethod
    def setTailAux(root, tail, pTail):
        # Statement 
        current = root.getRequiredProperty(pTail)
        # Resource 
        oldTail = current.getResource()

        # out with the old, in with the new
        current.remove()
        root.addProperty(pTail, tail)

        return oldTail
    


#==============================================================================
# Inner class definitions
#==============================================================================

'''
 * <p>
 * Iterator that can step along chains of list pointers to the end of the
 * list.
 * </p>
'''
# NiceIterator<RDFNode>
class RDFListIterator(NiceIterator):
    # Instance variables

    '''
     * The current list node
    '''
    # protected RDFList
    m_head = None

    '''
     * The most recently seen node
    '''
    # protected RDFList
    m_seen = None


    # Constructor
    #######

    '''
     * Construct an iterator for walking the list starting at head
    '''
    # RDFList
    def __init__(self, head):
        self.m_head = head



    # External contract methods
    ##############

    '''
     * @see Iterator#hasNext
    '''
    # @Override
    # param
    # result boolean
    def hasNext(self):
        return not self.m_head.isEmpty()


    '''
     * @see Iterator#next
    '''
    # @Override
    # param
    # result RDFNode
    def next(self):
        self.m_seen = self.m_head
        self.m_head = self.m_head.getTail()

        return self.m_seen.getHead()


    '''
     * @see Iterator#remove
    '''
    # @Override
    # param
    # result void
    def remove(self):
        if (self.m_seen is None):
            raise IllegalStateException("Illegal remove from list operator")


        # will remove three statements in a well-formed list
        # ((Resource) m_seen).removeProperties()
        self.m_seen.removeProperties()
        self.m_seen = None
        
    

